using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json.Linq;

namespace JsonRpcGen.ParameterHandler
{
    internal class ParamsHandler
    {
        public List<ParamHandler> Params= new List<ParamHandler>();

        private int OverLoadDimensions;

        public ParamsHandler(JToken parameters, Dictionary<string, string> replacements, string methodName, string objectTypePrefix)
        {
            foreach (JObject parameter in parameters)
            {
                var name = parameter["name"].ToString();

                var paramHandler = GetParamHandler(parameter, name, replacements, methodName, objectTypePrefix + name + "Type",
                                                   name + "Enum");
                Params.Add(paramHandler);
                if (paramHandler is OverloadParamHandler)
                {
                    OverloadHandler = (OverloadParamHandler) paramHandler;
                    OverLoadDimensions++;
                    if (OverLoadDimensions > 1)
                    {
                        throw new NotImplementedException();
                    }
                }
            }
        }

        public static ParamHandler GetParamHandler(JToken parameter, string name, Dictionary<string, string> replacements, string methodName, string objectName, string enumName)
        {
            var refName = parameter["$ref"];
            if (refName != null)
            {
                var refName2 = Global.GetRefName(refName.ToString(), replacements);
                return new ParamHandler(name, refName2);
            }
            var type = parameter["type"].ToString();
            switch (type)
            {
                case "array":
                    return new ArrayParamHandler(name, parameter, replacements);
                case "object":
                    return new ObjectParamHandler(name, parameter, objectName);
                case "string":
                    if (parameter["enums"] != null)
                    {
                        return new EnumParamHandler(name, parameter["enums"], enumName);
                    }
                    return new ParamHandler(name, "string");
                case "integer":
                    return new ParamHandler(name, "int");
                case "number":
                    return new ParamHandler(name, "double");
                case "boolean":
                    return new ParamHandler(name, "bool");
                default:
                    if (parameter["type"].Count() == 2 && parameter["type"].First["type"] != null
                        && parameter["type"].First["type"].ToString() == "null" && parameter["type"].Last["$ref"] != null
                        && parameter["type"].Last["$ref"].ToString() == "Array.String")
                    {
                        return new ParamHandler(name, "string[]");
                    }
                    return new OverloadParamHandler(name, parameter, replacements, methodName);
            }
        }

        protected OverloadParamHandler OverloadHandler { get; set; }

        public int GetOverloadCount()
        {
            if (OverloadHandler!=null)
            {
                return OverloadHandler.Count;
            }
            return 1;
        }

        public void SetOverload(int overload)
        {
            if(OverloadHandler!=null)
            {
                OverloadHandler.SetOverload(overload);
            }
        }

        public string GetParamList()
        {
            return string.Join(", ", Params.Where(p=>p.OriginalName!=null).Select(p=> p.Type + " " + p.Name + "=" + p.GetDefault()));
        }

        public void WriteTypes(StreamWriter writer, Dictionary<string, string> replacements)
        {
            foreach (var paramHandler in Params)
            {
                paramHandler.WriteType(writer, replacements);
            }
        }

        public IEnumerable<ParamHandler> GetNames()
        {
            return Params.Where(p=>p.OriginalName!=null);
        }
    }
}